/**
 * 常量池
 * User: Zhikang.Peng
 * Date: 2018/04/26 16:20
 */
package heap

import (
	"fmt"
	"gitee.com/thghh/jvmgo/classfile"
)

type Constant interface{}

type ConstantPool struct {
	class     *Class
	constants []Constant
}

func newConstantPool(class *Class, cfCp classfile.ConstantPool) *ConstantPool {
	cpCount := len(cfCp)
	constants := make([]Constant, cpCount)
	// run time constant pool
	rtCp := &ConstantPool{class, constants}
	for i := 1; i < cpCount; i++ {
		cpInfo := cfCp[i]
		switch cpInfo.(type) {
		case *classfile.ConstantIntegerInfo: // int32
			info := cpInfo.(*classfile.ConstantIntegerInfo)
			constants[i] = info.Value()
		case *classfile.ConstantLongInfo: // long(int64)
			info := cpInfo.(*classfile.ConstantLongInfo)
			constants[i] = info.Value()
			i++
		case *classfile.ConstantFloatInfo: // float32
			info := cpInfo.(*classfile.ConstantFloatInfo)
			constants[i] = info.Value()
		case *classfile.ConstantDoubleInfo: // double(float64)
			info := cpInfo.(*classfile.ConstantDoubleInfo)
			constants[i] = info.Value()
			i++
		case *classfile.ConstantStringInfo: // string
			info := cpInfo.(*classfile.ConstantStringInfo)
			constants[i] = info.String()
		case *classfile.ConstantClassInfo: // class
			info := cpInfo.(*classfile.ConstantClassInfo)
			constants[i] = newClassRef(rtCp, info)
		case *classfile.ConstantFieldrefInfo: // field
			info := cpInfo.(*classfile.ConstantFieldrefInfo)
			constants[i] = newFieldRef(rtCp, info)
		case *classfile.ConstantMethodrefInfo: // method
			info := cpInfo.(*classfile.ConstantMethodrefInfo)
			constants[i] = newMethodRef(rtCp, info)
		case *classfile.ConstantInterfaceMethodrefInfo: // interface method
			info := cpInfo.(*classfile.ConstantInterfaceMethodrefInfo)
			constants[i] = newInterfaceMethodRef(rtCp, info)
		default:
			// todo
		}
	}
	return rtCp
}

func (self *ConstantPool) GetConstant(index uint) Constant {
	c := self.constants[index]
	if c != nil {
		return c
	}
	panic(fmt.Sprintf("No constant at index %d", index))
}
